package com.ljqc.sbom.management.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.hutool.core.bean.BeanUtil;
import com.google.common.collect.Lists;
import com.ljqc.sbom.management.constant.Constant;
import com.ljqc.sbom.management.domain.SpdxLicense;
import com.ljqc.sbom.management.domain.SpdxVul;
import com.ljqc.sbom.management.dto.SpdxSbomDTO;
import com.ljqc.sbom.management.service.DataClientService;
import com.ljqc.sbom.management.service.RepositoryTransfer;
import com.ljqc.sbom.management.service.feignClient.dto.PlatformNameVersionListVO;
import com.ljqc.sbom.management.service.feignClient.dto.PlatformNameVersionReqVO;
import com.ljqc.sbom.management.service.feignClient.dto.PlatformNameVersionRespVO;
import com.ljqc.sbom.management.util.LicenseUtil;
import com.ljqc.sbom.management.util.VersionMatcher;
import com.ljqc.sbom.management.util.VulAndLicenseRiskUtil;
import cn.hutool.json.JSONUtil;
import org.apache.commons.io.IOUtils;
import org.spdx.tools.SpdxConverter;
import org.spdx.tools.Verify;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.ljqc.sbom.management.constant.Platform;
import com.ljqc.sbom.management.constant.SystemConstant;
import com.ljqc.sbom.management.domain.Account;
import com.ljqc.sbom.management.domain.SpdxPackage;
import com.ljqc.sbom.management.domain.SpdxProject;
import com.ljqc.sbom.management.domain.Vulnerability;
import com.ljqc.sbom.management.dto.SpdxIngredientDTO;
import com.ljqc.sbom.management.dto.SpdxLicenseParam;
import com.ljqc.sbom.management.dto.SpdxMQDto;
import com.ljqc.sbom.management.dto.SpdxPackageConditionDTO;
import com.ljqc.sbom.management.dto.SpdxPackageDTO;
import com.ljqc.sbom.management.dto.SpdxPackageParam;
import com.ljqc.sbom.management.dto.SpdxPackageStatisticDTO;
import com.ljqc.sbom.management.dto.SpdxProjectInfo;
import com.ljqc.sbom.management.dto.SpdxProjectInfoDTO;
import com.ljqc.sbom.management.dto.SpdxProjectLicenseInfoDTO;
import com.ljqc.sbom.management.dto.SpdxProjectSearchDTO;
import com.ljqc.sbom.management.dto.SpdxProjectVulInfoDTO;
import com.ljqc.sbom.management.dto.SpdxVulInfoDTO;
import com.ljqc.sbom.management.dto.SpdxVulListDTO;
import com.ljqc.sbom.management.enums.VulLevelEnum;
import com.ljqc.sbom.management.exception.BusinessException;
import com.ljqc.sbom.management.repository.AccountRepository;
import com.ljqc.sbom.management.repository.SpdxLicenseRepository;
import com.ljqc.sbom.management.repository.SpdxPackageRepository;
import com.ljqc.sbom.management.repository.SpdxProjectRepository;
import com.ljqc.sbom.management.repository.SpdxVulRepository;
import com.ljqc.sbom.management.service.FixService;
import com.ljqc.sbom.management.service.SpdxProjectService;
import com.ljqc.sbom.management.service.feignClient.KbApiService;
import com.ljqc.sbom.management.util.SpdxUtil;
import com.ljqc.sbom.management.util.ThreadLocalManager;
import com.ljqc.sbom.management.vo.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.spdx.library.model.license.ListedLicenses;
import org.spdx.tools.SpdxToolsHelper;
import org.spdx.tools.SpdxVerificationException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.JpaSort;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.data.domain.Sort;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SpdxProjectServiceImpl implements SpdxProjectService {

    @Autowired
    SpdxProjectRepository spdxProjectRepository;
    @Autowired
    SpdxVulRepository spdxVulRepository;
    @Autowired
    SpdxLicenseRepository spdxLicenseRepository;
    @Autowired
    AccountRepository accountRepository;
    @Autowired
    SpdxPackageRepository spdxPackageRepository;
    @Autowired
    DataClientService dataClientService;
    @Autowired
    RepositoryTransfer repositoryTransfer;
    @Autowired
    FixService fixService;
    @Autowired
    KbApiService kbApiService;

    @Autowired
    AmqpTemplate rabbitTemplate;

    private static List<String> listedLicenseIds = ListedLicenses.getListedLicenses().getSpdxListedLicenseIds();

    @Resource
    JdbcTemplate jdbcTemplate;

    @Override
    public Integer createSpdxProject(JSONObject param) {
        SpdxProject spdxProject = BeanUtil.toBean(param, SpdxProject.class);
        spdxProject.setCreateTime(System.currentTimeMillis());
        spdxProject.setUpdateTime(System.currentTimeMillis());
        spdxProject.setMsg("新建项目");
        spdxProject.setProgress(5);
        spdxProject.setLastScan(System.currentTimeMillis());
        spdxProjectRepository.saveAndFlush(spdxProject);
        return spdxProject.getId();
    }

    @Override
    public boolean spdxProjectNameCheck(String name) {
        Integer currentUserId = ThreadLocalManager.getCurrentUserId();
        Integer id = spdxProjectRepository.findSdpxProjectIdByNameAndUserId(name, currentUserId);
        return !ObjectUtils.isEmpty(id);
    }

    @Override
    public CommonResult deleteSpdxProjectByIds(List<String> ids) {
        List<Integer> validIds = ids.stream().map(Integer::new).collect(Collectors.toList());
        for (Integer id : validIds) {
            spdxProjectRepository.deleteById(id);
            deleteSpdxProject(id);
        }
        return new CommonResult(200, "删除成功");
    }

    @Transactional
    public void deleteSpdxProject(Integer id) {
        try {
            spdxPackageRepository.deleteAllBySpdxProjectId(id);
            spdxLicenseRepository.deleteAllBySpdxProjectId(id);
            spdxVulRepository.deleteAllBySpdxProjectId(id);
        } catch (Exception e) {
            log.error("delete spdx project {} error: {}", id, e);
        }

    }

    @Override
    public JSONObject getSpdxList(SpdxProjectSearchDTO dto) {
        Integer enterpriseId = getEnterpriseId();
        Integer userId = ThreadLocalManager.getCurrentUserId();
        Account account = accountRepository.getOne(userId);
        if (account.getRole() == 1) {
            userId = null;
        }
        String search = StringUtils.isBlank(dto.getSearch()) ? null : dto.getSearch().trim();
        List<Integer> vulLevel = null;
        if (!CollectionUtils.isEmpty(dto.getVulLevel())) {
            vulLevel = dto.getVulLevel();
        }
        Page<JSONObject> page = spdxProjectRepository.findSpdxProjectList(enterpriseId, search, vulLevel, userId,
                PageRequest.of(dto.getPage() - 1, dto.getPageSize()));
        List<JSONObject> projectParseInfoList = page.getContent();
        if (projectParseInfoList.size() > 0) {
            putSpdxProjectInfo(projectParseInfoList);
        }
        JSONObject res = new JSONObject();
        res.put("total_num", page.getTotalElements());
        res.put("project_info", projectParseInfoList);
        return res;
    }

    @Override
    public JSONObject getProjectInfoCount() {
        Integer enterpriseId = getEnterpriseId();
        Integer userId = ThreadLocalManager.getCurrentUserId();
        Account account = accountRepository.getOne(userId);
        if (account.getRole() == 1) {
            userId = null;
        }
        List<JSONObject> projectTotalInfo = spdxProjectRepository.getProjectTotalInfo(enterpriseId, userId);
        Map<Integer, Integer> defectVulLevelCount = new HashMap<>();
        projectTotalInfo.forEach(p -> {
            defectVulLevelCount.put(p.getInteger("value"), p.getInteger("count"));
        });
        JSONObject res = new JSONObject();
        res.put("defect_vul_count", defectVulLevelCount);
        return res;
    }

    @Override
    public CommonResult<SpdxProjectInfoDTO> getProjectInfo(Integer spdxProjectId) {
        SpdxProject project = spdxProjectRepository.getSpdxProjectById(spdxProjectId);
        if (ObjectUtils.isEmpty(project)) {
            return new CommonResult<>(500, "查询失败");
        }
        SpdxProjectInfoDTO spdxProjectInfoDTO = BeanUtil.toBean(project, SpdxProjectInfoDTO.class);
        Integer userId = project.getUserId();
        if (userId != null) {
            Account account = accountRepository.getOne(userId);
            spdxProjectInfoDTO.setAccount(account.getAccount());
        }

        return new CommonResult<>(200, spdxProjectInfoDTO, "");
    }

    @Override
    public SpdxProjectLicenseInfoDTO getSpdxProjectLicenseInfo(Integer spdxProjectId) {

        List<JSONObject> licenseDtos = spdxLicenseRepository.getLicenseBySpdxProjectId(spdxProjectId);
        // 风险等级数量分布
        List<Integer> riskLevels = Arrays.asList(0, 1, 2, 3);
        List<SpdxProjectLicenseInfoDTO.LicenseRiskInfo> licenseRiskInfos = licenseDtos.stream().map(data ->
                SpdxProjectLicenseInfoDTO.LicenseRiskInfo.builder()
                        .riskLevel(Integer.valueOf(data.get("risk_level").toString()))
                        .riskLevelCount(Integer.valueOf(data.get("license_count").toString()))
                        .build()
        ).collect(Collectors.toList());
        riskLevels.stream().forEach(level -> {
            if (licenseRiskInfos.stream().allMatch(data -> data.getRiskLevel() != level)) {
                licenseRiskInfos.add(SpdxProjectLicenseInfoDTO.LicenseRiskInfo.builder()
                        .riskLevel(level)
                        .riskLevelCount(0)
                        .build());
            }
        });

        // 许可证总数
        Integer licenseCount = licenseRiskInfos.stream().map(SpdxProjectLicenseInfoDTO.LicenseRiskInfo::getRiskLevelCount)
                .reduce(Integer::sum).orElse(0);

        // 高风险许可证总数
        Integer highLicenseCount = licenseRiskInfos.stream().filter(data -> data.getRiskLevel() == 3)
                .map(SpdxProjectLicenseInfoDTO.LicenseRiskInfo::getRiskLevelCount).findFirst().orElse(0);

        return SpdxProjectLicenseInfoDTO.builder()
                .licenseCount(licenseCount)
                .highLicenseCount(highLicenseCount)
                .licenseRiskInfos(licenseRiskInfos)
                .build();
    }

    @Override
    public CommonResult<SpdxProjectVulInfoDTO> getSpdxProjectVulInfo(Integer spdxProjectId) {
        SpdxProjectVulInfoDTO spdxProjectVulInfoDTO = new SpdxProjectVulInfoDTO();
        List<JSONObject> vulCountList = spdxVulRepository.getVulLevelCount(spdxProjectId);
        AtomicReference<Integer> vulCount = new AtomicReference<>(0);
        if (!CollectionUtils.isEmpty(vulCountList)) {
            vulCountList.forEach(data -> {
                Integer vul_level = data.getInteger("vul_level");
                Integer count = data.getInteger("count");
                vulCount.updateAndGet(v -> v + count);
                if (vul_level.equals(VulLevelEnum.UNKNOWN.getCode())) {
                    spdxProjectVulInfoDTO.setVulUnknown(count);
                } else if (vul_level.equals(VulLevelEnum.LOW.getCode())) {
                    spdxProjectVulInfoDTO.setVulLow(count);
                } else if (vul_level.equals(VulLevelEnum.MID.getCode())) {
                    spdxProjectVulInfoDTO.setVulMid(count);
                } else if (vul_level.equals(VulLevelEnum.HIGH.getCode())) {
                    spdxProjectVulInfoDTO.setVulHigh(count);
                } else {
                    spdxProjectVulInfoDTO.setVulCritical(count);
                }
            });
        }
        Integer packageCount = spdxPackageRepository.findPackageCount(spdxProjectId);
        spdxProjectVulInfoDTO.setPackageCount(packageCount);
        spdxProjectVulInfoDTO.setVulCount(vulCount.get());
        return new CommonResult<>(200, spdxProjectVulInfoDTO, "");
    }

    @Override
    public SpdxProject getSpdxProjectById(Integer spdxProjectId) {
        return spdxProjectRepository.getSpdxProjectById(spdxProjectId);
    }

    @Override
    @Async
    public void handleSpdxFileParse(JSONObject param) {
        Integer spdxProjectId = null;
        try {
            spdxProjectId = param.getInteger("spdxProjectId");
            String filePath = param.getString("filePath");
            Integer reload = param.getInteger("reload");

            SpdxProject spdxProject = spdxProjectRepository.getSpdxProjectById(spdxProjectId);
            if (spdxProject == null) {
                throw new BusinessException("spdx project find fail!");
            }
            spdxProject.setStatus(1);
            updateStatus(spdxProject, "项目解压中", 30);

            File file = new File(filePath);
            if (!file.exists()) {
                throw new BusinessException("文件不存在");
            }
            String absolutePath = file.getAbsolutePath();
            String fileName = file.getName();
            fileName = fileName.substring(0, fileName.lastIndexOf("."));
            String toFilePath = file.getParent() + File.separator + fileName + ".json";

            log.info("spdx parse start");
            if (reload != 1) {
                // 判断是否是spdx文件
                SpdxToolsHelper.SerFileType fileType = isSpdx(spdxProject, filePath);

                // 转换为json格式
                toFilePath = spdxToJsonFile(fileType, filePath, toFilePath);
            }

            String content = FileUtils.readFileToString(new File(toFilePath), "UTF-8");
            JSONObject jsonObject = JSON.parseObject(content);
            SpdxProjectInfo spdxProjectInfo = BeanUtil.toBean(jsonObject, SpdxProjectInfo.class);
            spdxProject = saveProjectInfo(spdxProjectInfo, spdxProjectId, absolutePath, fileName, jsonObject.toString());
            updateStatus(spdxProject, "项目解析中", 60);
            SpdxMQDto mqDto = SpdxMQDto.builder()
                    .spdxProjectId(spdxProjectId)
                    .dirPath(toFilePath)
                    .build();
            rabbitTemplate.convertAndSend("spdx", JSONObject.toJSONString(mqDto));

        } catch (Exception e) {
            log.error("spdx parse fail", e);
            if (Objects.nonNull(spdxProjectId)) {
                updateStatusById(spdxProjectId, "解析失败", -1);
            }
        }

    }

    private SpdxProject saveProjectInfo(SpdxProjectInfo spdxProjectInfo, Integer spdxProjectId, String path, String fileName, String result) {
        SpdxProject spdxProject = spdxProjectRepository.getSpdxProjectById(spdxProjectId);
        spdxProject.setSpdxId(spdxProjectInfo.getSPDXID());
        spdxProject.setProjectVersion(spdxProjectInfo.getSpdxVersion());
        spdxProject.setProjectLicense(spdxProjectInfo.getDataLicense());
        spdxProject.setProjectLicense(spdxProjectInfo.getDataLicense());
        spdxProject.setDocumentName(spdxProjectInfo.getName());
        spdxProject.setDocumentComment(spdxProjectInfo.getComment());
        spdxProject.setDocumentNamespace(spdxProjectInfo.getDocumentNamespace());
        spdxProject.setFilePath(path);
        spdxProject.setFileName(fileName);
        spdxProject.setLastScan(System.currentTimeMillis());
//        spdxProject.setResult(result);
        SpdxProjectInfo.CreationInfo creationInfo = spdxProjectInfo.getCreationInfo();
        if (creationInfo != null) {
            if (!CollectionUtils.isEmpty(creationInfo.getCreators())) {
                List<String> creators = creationInfo.getCreators();
                creators.forEach(data -> {
                    String value = data.substring(data.lastIndexOf(":") + 2);
                    if (data.contains("Person")) {
                        spdxProject.setCreatorPerson(value);
                    } else if (data.contains("Organization")) {
                        spdxProject.setCreatorOrganization(value);
                    } else if (data.contains("Tool")) {
                        spdxProject.setCreatorTool(value);
                    }
                });
            }
            spdxProject.setCreated(creationInfo.getCreated());
            spdxProject.setCreatorComment(creationInfo.getComment());
            spdxProject.setLicenseListVersion(creationInfo.getLicenseListVersion());
        }

        spdxProjectRepository.saveAndFlush(spdxProject);
        return spdxProject;
    }


    private SpdxToolsHelper.SerFileType isSpdx(SpdxProject spdxProject, String filePath) throws SpdxVerificationException {
        SpdxToolsHelper.SerFileType fileType = SpdxUtil.formatIntegerToSpdx(spdxProject.getType());
        if (fileType == null) {
            throw new BusinessException("spdx format error");
        }

        // 判断是否是spdx文件
        if (!fileType.equals(SpdxToolsHelper.SerFileType.XML)) {
            List<String> result = Verify.verify(filePath, fileType);
            if (result.size() > 0) {
                throw new BusinessException("spdx verify fail!");
            }
        }
        return fileType;
    }

    @Override
    public void updateStatus(SpdxProject spdxProject, String msg, Integer progress) {
        spdxProject.setMsg(msg);
        spdxProject.setProgress(progress);
        spdxProject.setLastScan(System.currentTimeMillis());
        spdxProjectRepository.saveAndFlush(spdxProject);
    }

    @Override
    public SpdxPackage getPackageSolution(SpdxPackage spdxPackage) {
        String platform = spdxPackage.getPlatform();
        String version = spdxPackage.getVersion();
        Integer moveTo = spdxPackage.getMoveTo();
        Integer packageId = spdxPackage.getLjPackageId();
        String repoName = spdxPackage.getRepoName();
        Map<Integer, String> map = repositoryTransfer.getMoveToSolution(platform, moveTo);
        if (map == null || map.size() == 0) {
            if (!(Platform.npm.name().equals(platform) || Platform.yarn.name().equals(platform) || Platform.packagist.name().equals(platform))) {
                List<String> versionList = fixService.getSolutionVersion(platform, packageId, version);
                String cleanVersion = VersionMatcher.getMavenCleanVersion(versionList, version);
                if (!StringUtils.isBlank(cleanVersion)) {
                    spdxPackage.setCleanVersion(cleanVersion);
                    String solution = "请将" + repoName + "升级为" + cleanVersion + "版本";
                    spdxPackage.setSolution(solution);
                }
            }
        } else {
            String solve = map.get(moveTo);
            spdxPackage.setMoveToSolution(solve);
        }
        return spdxPackage;
    }

    @Override
    public void updateStatusById(Integer id, String msg, Integer status) {
        spdxProjectRepository.updateStatusById(id, msg, status);
    }

    @Override
    public JSONObject getSpdxPackageList(SpdxPackageParam spdxPackageParam) {
        JSONObject jsonObject = new JSONObject();
        Pageable page = getPageable(spdxPackageParam.getPageNo(), spdxPackageParam.getPageSize(), spdxPackageParam.getOrderNameList(), spdxPackageParam.getOrderRule());
        Page<JSONObject> packageList = spdxPackageRepository.getPackageList(spdxPackageParam.getProjectId(), spdxPackageParam.getRepoName()
                , spdxPackageParam.getPlatform(), spdxPackageParam.getInhouse(), page);
        List<JSONObject> content = packageList.getContent();
        List<SpdxPackageDTO> collect = new ArrayList<>();
        if (!CollectionUtils.isEmpty(content)) {
            collect = content.stream().map(SpdxProjectServiceImpl::convertToPackageDto).collect(Collectors.toList());
        }
        collect.forEach(data -> {
            String licenseDeclared = data.getLicenseDeclared();
            String license = data.getLicense();
            if (StringUtils.isNotEmpty(license)) {
                data.setLicenses(Arrays.asList(license.split(",")));
            }

            if (StringUtils.isNotEmpty(licenseDeclared)) {
                data.setLicenseDeclaredRelation(licenseDeclared.contains("OR") ? 1 : licenseDeclared.contains("AND") ? 2 : 0);
                data.setLicenseDeclareds(licenseConvertList(licenseDeclared));
            } else {
                data.setLicenseDeclaredRelation(0);
                data.setLicenseDeclareds(null);
            }
        });
        jsonObject.put("records", collect);
        jsonObject.put("total", packageList.getTotalElements());
        return jsonObject;
    }

    @Override
    public SpdxPackageConditionDTO getPackageCondition(Integer spdxProjectId) {
        SpdxPackageConditionDTO spdxPackageConditionDto = new SpdxPackageConditionDTO();
        spdxPackageConditionDto.setPlatformList(spdxPackageRepository.getPlatformList(spdxProjectId));
        return spdxPackageConditionDto;
    }

    @Override
    public SpdxPackageStatisticDTO getStatistic(Integer spdxProjectId) {
        SpdxPackageStatisticDTO dto = new SpdxPackageStatisticDTO();
        HashMap<String, Object> securityMap = Maps.newHashMap();
        HashMap<String, Object> licenseMap = Maps.newHashMap();

        // 安全风险-统计
        List<JSONObject> vulLevelList = spdxPackageRepository.getCountByVulLevel(spdxProjectId);

        if (CollectionUtils.isEmpty(vulLevelList)) {
            securityMap.put(SystemConstant.SERIOUS, 0);
            securityMap.put(SystemConstant.HIGH, 0);
            securityMap.put(SystemConstant.MID, 0);
            securityMap.put(SystemConstant.LOW, 0);
            securityMap.put(SystemConstant.NOT_RATED, 0);
        } else {
            for (JSONObject json : vulLevelList) {
                buildSecurityAndLicenseMap(securityMap, json);
            }
        }

        if (MapUtils.isNotEmpty(securityMap)) {
            if (!securityMap.containsKey(SystemConstant.SERIOUS)) {
                securityMap.put(SystemConstant.SERIOUS, 0);
            }
            buildMapEmptyData(securityMap);
        }

        securityMap.put(SystemConstant.NO_RISK, spdxPackageRepository.getCountNoVulLevel(spdxProjectId));


        // 许可证风险-统计
        List<JSONObject> licenseLevelList = spdxPackageRepository.getCountByLicenseLevel(spdxProjectId);
        if (CollectionUtils.isEmpty(licenseLevelList)) {
            licenseMap.put(SystemConstant.HIGH, 0);
            licenseMap.put(SystemConstant.MID, 0);
            licenseMap.put(SystemConstant.LOW, 0);
            licenseMap.put(SystemConstant.NOT_RATED, 0);
        } else {
            for (JSONObject json : licenseLevelList) {
                buildSecurityAndLicenseMap(licenseMap, json);
            }
        }

        if (!CollectionUtils.isEmpty(licenseMap)) {
            buildMapEmptyData(licenseMap);
        }

        licenseMap.put(SystemConstant.UN_DECLARED, spdxPackageRepository.getCountByNoLicenseLevel(spdxProjectId));
        dto.setLicenseMap(licenseMap);
        dto.setSecurityMap(securityMap);

        return dto;
    }

    @Override
    public JSONObject getSpdxLicenseList(SpdxLicenseParam spdxLicenseParam) {
        JSONObject jsonObject = new JSONObject();
        String orderType = spdxLicenseParam.getOrderType();
        String orderName = spdxLicenseParam.getOrderName();
        JpaSort jpaSort = null;
        if ("desc".equals(orderType)) {
            jpaSort = JpaSort.unsafe(Sort.Direction.DESC, orderName, "id");
        } else {
            jpaSort = JpaSort.unsafe(Sort.Direction.ASC, orderName, "id");
        }
        Pageable page = PageRequest.of(spdxLicenseParam.getPageNo() - 1, spdxLicenseParam.getPageSize(), jpaSort);
        Page<JSONObject> licenseList = spdxLicenseRepository.getLicenseList(spdxLicenseParam.getProjectId(), spdxLicenseParam.getLicense(), spdxLicenseParam.getRiskLevel(), page);
        jsonObject.put("records", licenseList.getContent());
        jsonObject.put("total", licenseList.getTotalElements());
        return jsonObject;
    }

    @Override
    public List<String> getLicenseAll(Integer spdxProjectId) {
        return spdxLicenseRepository.getLicenseAll(spdxProjectId);
    }

    @Override
    public JSONObject getPackageDetailList(Integer spdxProjectId, String name, int fileType, Integer pageNo, Integer pageSize) {
        JSONObject jsonObject = new JSONObject();
        Page<JSONObject> list = null;
        if (fileType == 1) {
            list = spdxPackageRepository.getPackageByLicense(spdxProjectId, name, PageRequest.of(pageNo - 1, pageSize));
        } else if (fileType == 2) {
            list = spdxPackageRepository.getPackageByVul(spdxProjectId, name, PageRequest.of(pageNo - 1, pageSize));
        }
        jsonObject.put("total", list != null ? list.getTotalElements() : 0);
        jsonObject.put("records", list != null ? list.getContent() : null);
        return jsonObject;
    }

    @Override
    public List<String> getVulPackages(Integer spdxProjectId) {
        return spdxVulRepository.getVulPackages(spdxProjectId);
    }

    @Override
    public JSONObject getIngredientList(SpdxIngredientDTO spdxIngredientDTO) {
        JSONObject jsonObject = new JSONObject();
        Pageable page = PageRequest.of(spdxIngredientDTO.getPageNo() - 1, spdxIngredientDTO.getPageSize());
        Page<JSONObject> ingredientList = spdxVulRepository.getIngredientList(spdxIngredientDTO.getVulLevel(), spdxIngredientDTO.getPlatform(),
                spdxIngredientDTO.getLjVulScoreMax(), spdxIngredientDTO.getLjVulScoreMin(), spdxIngredientDTO.getProjectId(), spdxIngredientDTO.getName(), page);
        jsonObject.put("total", ingredientList.getTotalElements());
        jsonObject.put("content", ingredientList.getContent());
        return jsonObject;
    }

    @Override
    public JSONObject getVulInfo(Integer spdxProjectId, Integer spdxPackageId, String field, String order, Integer ljVulScoreMax, Integer ljVulScoreMin, Integer pageNo, Integer pageSize) {
        JSONObject jsonObject = new JSONObject();
        Sort sort;
        if (Objects.equals("cvss_score", field)) {
            sort = buildSortCvssScore(field, order);
        } else {
            List<Sort.Order> orders = new ArrayList<Sort.Order>();
            Sort.Order orderColumn = this.buildOrder(field, order);
            orders.add(orderColumn);
            sort = Sort.by(orders);
        }
        Pageable page = PageRequest.of(pageNo - 1, pageSize, sort);

        Page<JSONObject> vulInfoList = spdxVulRepository.getVulDetail(spdxProjectId, spdxPackageId, ljVulScoreMax, ljVulScoreMin, page);
        List<SpdxVulInfoDTO> collect = vulInfoList.getContent().stream().map(data -> {
            return SpdxVulInfoDTO.builder()
                    .vulId(data.getString("vul_id"))
                    .cveId(data.getString("cve_id"))
                    .vulTitle(data.getString("vul_title"))
                    .vulLevel(data.getInteger("vul_level"))
                    .cvssScore(data.getFloat("cvss_score"))
                    .ljVulScore(data.getBigDecimal("lj_vul_score"))
                    .exposureLevel(data.getInteger("exposure_level"))
                    .cwes(data.getString("cwes"))
                    .vulPublished(data.getString("vul_published"))
                    .solveFlag((StringUtils.isEmpty(data.getString("solve")) || data.getString("solve").indexOf("暂无") > 0) ? 0 : 1)
                    .build();
        }).collect(Collectors.toList());

        SpdxPackage spdxPackage = spdxPackageRepository.getSpdxPackageById(spdxPackageId);
        List<String> paths = spdxPackageRepository.getPackageFilePath(spdxPackage.getRepoName(), spdxPackage.getPlatform(), spdxPackage.getVersion(), spdxProjectId);

        if (!CollectionUtils.isEmpty(collect)) {
            Map<String, SpdxVulInfoDTO> vulMap = collect.stream().collect(Collectors.toMap(SpdxVulInfoDTO::getVulId, Function.identity()));
            List<String> vulIds = new ArrayList<>(vulMap.keySet());
            List<Vulnerability> vulList1 = kbApiService.getVulList(vulIds);
            vulList1.forEach(x -> {
                SpdxVulInfoDTO obj = vulMap.get(x.getPkgVulId());
                if (obj != null) {
                    obj.setCweList(x.getCweList());
                }
            });
        }
        jsonObject.put("vulInfoList", collect);
        jsonObject.put("paths", paths);
        jsonObject.put("total", vulInfoList.getTotalElements());

        return jsonObject;
    }

    @Override
    public JSONObject getAllVul(SpdxVulListDTO spdxVulListDTO) {
        JSONObject jsonObject = new JSONObject();
        String field = spdxVulListDTO.getField();
        String order = spdxVulListDTO.getOrder();
        Sort sort;
        if (Objects.equals("cvss_score", field)) {
            sort = buildSortCvssScore(field, order);
        } else {
            List<Sort.Order> orders = new ArrayList<Sort.Order>();
            Sort.Order orderColumn = this.buildOrder(field, order);
            orders.add(orderColumn);
            sort = Sort.by(orders);
        }
        Pageable page = PageRequest.of(spdxVulListDTO.getPageNo() - 1, spdxVulListDTO.getPageSize(), sort);
        Page<JSONObject> vulList = spdxVulRepository.getVulList(spdxVulListDTO.getProjectId(), spdxVulListDTO.getVulId(), spdxVulListDTO.getVulLevels(),
                spdxVulListDTO.getLjVulScoreMax(), spdxVulListDTO.getLjVulScoreMin(), page);

        List<JSONObject> content = vulList.getContent();
        if (!CollectionUtils.isEmpty(content)) {
            Map<String, JSONObject> vulMap = content.stream().collect(Collectors.toMap(x -> x.getString("vulId"), Function.identity()));
            List<String> vulIds = new ArrayList<>(vulMap.keySet());
            List<Vulnerability> vulList1 = kbApiService.getVulList(vulIds);
            vulList1.forEach(x -> {
                JSONObject obj = vulMap.get(x.getPkgVulId());
                if (obj != null) {
                    obj.put("cweList", x.getCweList());
                }
            });
        }
        jsonObject.put("records", vulList.getContent());
        jsonObject.put("total", vulList.getTotalElements());
        return jsonObject;
    }

    private JpaSort buildSortCvssScore(String field, String order) {
        JpaSort jpaSort = null;
        if ("desc".equals(order)) {
            if (Objects.equals(field, "cvss_score")) {
                jpaSort = JpaSort.unsafe(Sort.Direction.DESC, "CONVERT (" + field + ", DECIMAL(10,2))");
            } else {
                jpaSort = JpaSort.unsafe(Sort.Direction.DESC, field);
            }
        } else {
            if (Objects.equals(field, "cvss_score")) {
                jpaSort = JpaSort.unsafe(Sort.Direction.ASC, "CONVERT (" + field + ", DECIMAL(10,2))");
            } else {
                jpaSort = JpaSort.unsafe(Sort.Direction.ASC, field);
            }
        }
        return jpaSort;
    }

    private Sort.Order buildOrder(String field, String order) {
        if ("desc".equals(order)) {
            return new Sort.Order(Sort.Direction.DESC, field);
        } else {
            return new Sort.Order(Sort.Direction.ASC, field);
        }
    }


    /**
     * 查询SBOM相关数据信息
     *
     * @param spdxProjectId
     * @return
     */
    @Override
    public SpdxSbomDTO getSbomInfo(Integer spdxProjectId) {

        //获取项目信息
        SpdxProject project = spdxProjectRepository.getSpdxProjectById(spdxProjectId);
        //判断项目是否为空，以及是否检测成功
        if (ObjectUtils.isEmpty(project)) {
            throw new BusinessException("spdx project find fail!");
        }
        //获取组件信息
        List<SpdxPackage> packages = queryPackages(spdxProjectId);

        return SpdxSbomDTO.builder().project(project).packages(packages).build();
    }

    private List<SpdxPackage> queryPackages(Integer spdxProjectId) {
        return spdxPackageRepository.findPackageByProjectId(spdxProjectId);
    }

    public static SpdxPackageDTO convertToPackageDto(JSONObject jsonObject) {
        SpdxPackageDTO spdxPackageDTO = BeanUtil.toBean(jsonObject, SpdxPackageDTO.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("critical", jsonObject.getInteger("critical") != null ? jsonObject.getInteger("critical") : 0);
        map.put("high", jsonObject.getInteger("high") != null ? jsonObject.getInteger("high") : 0);
        map.put("mid", jsonObject.getInteger("mid") != null ? jsonObject.getInteger("mid") : 0);
        map.put("low", jsonObject.getInteger("low") != null ? jsonObject.getInteger("low") : 0);
        map.put("unknown", jsonObject.getInteger("unknow") != null ? jsonObject.getInteger("unknow") : 0);
        spdxPackageDTO.setVulMap(map);
        return spdxPackageDTO;
    }

    private void buildSecurityAndLicenseMap(HashMap<String, Object> map, JSONObject obj) {
        Object level = obj.get(SystemConstant.LEVEL);
        if (level instanceof Number) {
            level = Integer.parseInt(level.toString());
        }
        Integer count = obj.getInteger(SystemConstant.COUNT);
        // 严重
        if (SystemConstant.INT_4 == level) {
            map.put(SystemConstant.SERIOUS, count);
        }
        // 高危
        if (SystemConstant.INT_3 == level) {
            map.put(SystemConstant.HIGH, count);
        }
        // 中危
        if (SystemConstant.INT_2 == level) {
            map.put(SystemConstant.MID, count);
        }
        // 低危
        if (SystemConstant.INT_1 == level) {
            map.put(SystemConstant.LOW, count);
        }
        // 未评级
        if (SystemConstant.INT_0 == level) {
            map.put(SystemConstant.NOT_RATED, count);
        }
    }

    private void buildMapEmptyData(HashMap<String, Object> map) {
        if (!map.containsKey(SystemConstant.HIGH)) {
            map.put(SystemConstant.HIGH, 0);
        }
        if (!map.containsKey(SystemConstant.MID)) {
            map.put(SystemConstant.MID, 0);
        }
        if (!map.containsKey(SystemConstant.LOW)) {
            map.put(SystemConstant.LOW, 0);
        }
        if (!map.containsKey(SystemConstant.NOT_RATED)) {
            map.put(SystemConstant.NOT_RATED, 0);
        }
    }

    private Pageable getPageable(Integer pageNo, Integer pageSize, List<String> orderNameList, String orderRule) {
        // 构建排序及分页信息
        ArrayList<Sort.Order> orderList = Lists.newArrayList();
        for (String orderName : orderNameList) {
            Sort.Order order = new Sort.Order(Sort.Direction.valueOf(orderRule), orderName);
            orderList.add(order);
        }
        Sort.Order order = new Sort.Order(Sort.Direction.valueOf(orderRule), "vi.id");
        orderList.add(order);
        Sort sort = Sort.by(orderList);
        return PageRequest.of(pageNo - 1, pageSize, sort);
    }


    public void savePackageData(SpdxProjectInfo spdxProjectInfo, Integer spdxProjectId) {
        List<SpdxProjectInfo.Package> packages = spdxProjectInfo.getPackages();
        List<SpdxPackage> list = packages.stream().map(x -> getSpdxPackage(x, spdxProjectInfo, spdxProjectId)).collect(Collectors.toList());
        // 保存组件
        spdxPackageRepository.saveAll(list);

        // 过滤没有包管理器的组件
        List<SpdxPackage> packageList = list.stream().filter(x -> StringUtils.isNotEmpty(x.getPlatform()) && StringUtils.isNotEmpty(x.getRepoName())
                && StringUtils.isNotEmpty(x.getVersion())).collect(Collectors.toList());

        PlatformNameVersionReqVO platformNameVersionReqVO = new PlatformNameVersionReqVO();
        List<PlatformNameVersionListVO> platformNameVersionListVOList = new ArrayList<>();
        packageList.forEach(data -> {
            PlatformNameVersionListVO platformNameVersionListVO = PlatformNameVersionListVO.builder()
                    .id(data.getId())
                    .platform(data.getPlatform())
                    .name(data.getRepoName())
                    .version(data.getVersion())
                    .build();
            platformNameVersionListVOList.add(platformNameVersionListVO);
        });

        if (platformNameVersionListVOList.size() > 0) {
            platformNameVersionReqVO.setReqListVOS(platformNameVersionListVOList);
        } else {
            return;
        }
        log.info("start findListByPlatformAndNameAndVersion, size: {}", platformNameVersionReqVO.getReqListVOS().size());
        List<PlatformNameVersionRespVO> data = dataClientService.findListByPlatformAndNameAndVersion(platformNameVersionReqVO).getData();
        log.info("end findListByPlatformAndNameAndVersion");

        // 更新组件
        updatePackages(data);
        log.info("end update package");

        // 保存许可证
        insertPackageLicense(data, spdxProjectId);

        // 保存漏洞
        insertPackageVul(data, spdxProjectId);
        log.info("end update vul");
    }

    private void updatePackages(List<PlatformNameVersionRespVO> data) {
        List<SpdxPackage> spdxPackageList = new ArrayList<>();
        data.forEach(p -> {
            SpdxPackage spdxPackage = spdxPackageRepository.getSpdxPackageById(p.getId());
            spdxPackage.setLjPackageId(p.getLjPackageId());
            spdxPackage.setMoveTo(p.getMoveTo());
            spdxPackage.setInhouse(p.getIsOpen());
            spdxPackage.setLicense(p.getVerifiedLicense());
            spdxPackage.setLicenseRelation(p.getLicenseRelation());
            if (spdxPackage.getMoveTo() != null && spdxPackage.getPlatform() != null && spdxPackage.getVersion() != null) {
                spdxPackage = getPackageSolution(spdxPackage);
            }
            spdxPackageList.add(spdxPackage);
        });
        spdxPackageRepository.saveAll(spdxPackageList);
    }

    private void insertPackageLicense(List<PlatformNameVersionRespVO> platformNameVersionRespVOList, Integer spdxProjectId) {
        List<SpdxLicense> list = new ArrayList<>();
        platformNameVersionRespVOList.stream().filter(data -> !CollectionUtils.isEmpty(data.getLicenseVOS())).forEach(data -> data.getLicenseVOS().forEach(l -> {
            if (!l.getLicenseRiskLevel().equals("未知")) {
                SpdxLicense spdxLicense = SpdxLicense.builder()
                        .spdxProjectId(spdxProjectId)
                        .spdxPackageId(data.getId())
                        .riskLevel(LicenseUtil.getLicenseRiskLevel(l.getLicenseRiskLevel()))
                        .category(l.getCategoryCh())
                        .license(l.getLjLicenseKey())
                        .build();
                list.add(spdxLicense);
            }
        }));
        spdxLicenseRepository.saveAll(list);
    }

    private void insertPackageVul(List<PlatformNameVersionRespVO> platformNameVersionRespVOList, Integer spdxProjectId) {
        List<SpdxVul> list = new ArrayList<>();
        platformNameVersionRespVOList.stream().filter(data -> !CollectionUtils.isEmpty(data.getVulPackageInfoVOS())).forEach(data -> data.getVulPackageInfoVOS().forEach(v -> {
            String formatCVSS;
            String vulAV = null;
            if (v.getCvss3Vector() != null) {
                formatCVSS = getFormatCVSS(v.getCvss3Vector(), 3);
            } else {
                formatCVSS = getFormatCVSS(v.getCvss2Vector(), 2);
            }

            JSONObject jsonObject = JSONObject.parseObject(formatCVSS);
            if (jsonObject != null) {
                vulAV = jsonObject.getString("av");
            }

            String cvssScore = "0.0";
            if (v.getCvss3BaseScore() != null) {
                cvssScore = v.getCvss3BaseScore().toString();
            } else if (v.getCvss2BaseScore() != null) {
                cvssScore = v.getCvss2BaseScore().toString();
            }

            SpdxVul spdxVul = SpdxVul.builder()
                    .spdxProjectId(spdxProjectId)
                    .spdxPackageId(data.getId())
                    .vulId(v.getPkgVulId())
                    .cveId(v.getCveId())
                    .cwes(v.getCwes())
                    .vulTitle(v.getTitleCn())
                    .vulLevel(VulAndLicenseRiskUtil.vul_cn(String.valueOf(v.getSeverity())))
                    .cvssScore(cvssScore)
                    .ljVulScore(setLjVulScore(spdxProjectId, v.getCveId(), cvssScore, vulAV))
                    .exposureLevel(v.getLevel())
                    .vulPublished(v.getPublishedTime())
                    .solve(v.getSolutionCn())
                    .build();
            list.add(spdxVul);
        }));
        spdxVulRepository.saveAll(list);
    }

    public BigDecimal setLjVulScore(int projectId, String cveId, String cvssScore, String vulAv) {
        BigDecimal pocExpNumber;
        BigDecimal netTypeNumber;
        BigDecimal accessTypeNumber;
        List<String> list = new ArrayList<>();
        if (StringUtils.isNotBlank(cveId)) {
            String pocExpSql = "select ext_type from vul_extinfo WHERE cve_id = '" + cveId + "'";
            try {
                list = jdbcTemplate.queryForList(pocExpSql, String.class);
            } catch (DataAccessException e) {
                log.error("vul_extinfo ext_type 查询失败：{}", e.getMessage());
            }
        }
        if (!list.isEmpty()) {
            if (!list.contains("poc") && !list.contains("exp")) {
                pocExpNumber = new BigDecimal("0.8");
            } else if (list.contains("poc") && list.contains("exp")) {
                pocExpNumber = new BigDecimal("1");
            } else {
                pocExpNumber = new BigDecimal("0.9");
            }
        } else {
            pocExpNumber = new BigDecimal("0.8");
        }

        String netTypeSql = "select net_type from spdx_project WHERE id = " + projectId;
        int netType = 1;
        try {
            netType = jdbcTemplate.queryForObject(netTypeSql, Integer.class);
        } catch (DataAccessException e) {
            log.error("project net_type 查询失败：{}", e.getMessage());
        }
        if (netType == 2) {
            netTypeNumber = new BigDecimal("0.9");
        } else {
            netTypeNumber = new BigDecimal("1");
        }

        if (null == vulAv || vulAv.isEmpty()) {
            accessTypeNumber = new BigDecimal("0.4");
        } else if ("network".equals(vulAv)) {
            accessTypeNumber = new BigDecimal("1");
        } else if ("local".equals(vulAv)) {
            accessTypeNumber = new BigDecimal("0.8");
        } else if ("physical".equals(vulAv)) {
            accessTypeNumber = new BigDecimal("0.6");
        } else {
            accessTypeNumber = new BigDecimal("0.4");
        }
        BigDecimal cvssNumber = new BigDecimal(cvssScore);
        BigDecimal zero = new BigDecimal("0.0");
        BigDecimal ljVulScore = zero;
        // 如果cvss评分大于0，则计算漏洞优先级评分，否则漏洞优先级评分为0
        if (zero.compareTo(cvssNumber) == -1) {
            ljVulScore = cvssNumber.multiply(pocExpNumber).multiply(netTypeNumber).multiply(accessTypeNumber).multiply(new BigDecimal("10"));
            // 漏洞优先级评分四舍五入保留一位小数
            ljVulScore = ljVulScore.setScale(1, BigDecimal.ROUND_HALF_UP);
        }
        return ljVulScore;
    }


    private SpdxPackage getSpdxPackage(SpdxProjectInfo.Package packageInfo, SpdxProjectInfo spdxProjectInfo, Integer spdxProjectId) {
        SpdxPackage spdxPackage = BeanUtil.toBean(packageInfo, SpdxPackage.class);
        String spdxId = packageInfo.getSPDXID();
        spdxPackage.setSpdxProjectId(spdxProjectId);
        spdxPackage.setRepoName(packageInfo.getName());
        spdxPackage.setVersion(packageInfo.getVersionInfo());
        spdxPackage.setHomePage(packageInfo.getHomepage());
        spdxPackage.setSpdxId(packageInfo.getSPDXID());
        if (packageInfo.getPackageVerificationCode() != null) {
            spdxPackage.setVerificationCode(packageInfo.getPackageVerificationCode().getPackageVerificationCodeValue());
        }
        // 组件检验和
        if (packageInfo.getChecksums() != null) {
            Map<String, String> collect = packageInfo.getChecksums().stream()
                    .collect(Collectors.toMap(SpdxProjectInfo.Checksum::getAlgorithm, SpdxProjectInfo.Checksum::getChecksumValue));
            spdxPackage.setChecksum(collect.toString());
        }

        // 包管理器
        if (packageInfo.getExternalRefs() != null) {
            List<SpdxProjectInfo.ExternalRef> externalRefs = packageInfo.getExternalRefs().stream()
                    .filter(e -> StringUtils.isNotEmpty(e.getReferenceLocator()) && e.getReferenceLocator().contains("pkg:")).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(externalRefs)) {
                String referenceLocator = externalRefs.get(0).getReferenceLocator();
                String platform = referenceLocator.substring(referenceLocator.indexOf(":") + 1, referenceLocator.indexOf("/"));
                spdxPackage.setPlatform(platform);
            }
        }

        // 组件依赖关系
        if (!CollectionUtils.isEmpty(spdxProjectInfo.getRelationships())) {
            StringBuilder sb = new StringBuilder();
            spdxProjectInfo.getRelationships().forEach(data -> {
                if (data.getRelationshipType() != null && data.getRelationshipType().equals("DEPENDS_ON")) {
                    if (data.getSpdxElementId() != null && data.getSpdxElementId().equals(spdxId)) {
                        sb.append(data.getRelatedSpdxElement()).append(",");
                    }
                }
            });
            if (sb.length() > 0) {
                sb.deleteCharAt(sb.length() - 1);
                spdxPackage.setRelationship(sb.toString());
            }
        }

        spdxPackage.setLicenseConcluded(conLicense(packageInfo.getLicenseConcluded()));
        spdxPackage.setLicenseDeclared(conLicense(packageInfo.getLicenseDeclared()));

        return spdxPackage;
    }

    private void putSpdxProjectInfo(List<JSONObject> projectInfoList) {
        projectInfoList.parallelStream().forEach(projectRes -> {
            Integer id = projectRes.getInteger("id");
            List<Map<Object, Object>> projectAllVul = spdxVulRepository.getAllProjectVulCount(id);
            Map<Integer, Object> projectVul = new HashMap<>();
            for (Map<Object, Object> map : projectAllVul) {
                Object vulLevel = Integer.parseInt(map.get("level") == null ? "0" : map.get("level").toString());
                Integer count = Integer.valueOf(map.get("count").toString());
                if (Constant.SUPER_VUL.equals(vulLevel)) {
                    projectVul.put(Constant.SUPER_VUL, count);
                } else if (Constant.HIGH_VUL.equals(vulLevel)) {
                    projectVul.put(Constant.HIGH_VUL, count);
                } else if (Constant.MID_VUL.equals(vulLevel)) {
                    projectVul.put(Constant.MID_VUL, count);
                } else if (Constant.LOW_VUL.equals(vulLevel)) {
                    projectVul.put(Constant.LOW_VUL, count);
                } else if (Constant.UNKNOWN_VUL.equals(vulLevel)) {
                    projectVul.put(Constant.UNKNOWN_VUL, count);
                }
            }

            List<Map<String, Object>> licenseRisk = spdxLicenseRepository.getLicenseAllRisk(id);
            licenseRisk = licenseRisk.stream().filter(x -> x != null && x.get("level") != null).collect(Collectors.toList());
            Map<Object, Long> level = licenseRisk.stream().collect(Collectors.groupingBy(x -> x.get("level"), Collectors.counting()));
            Map<Integer, Object> projectLicenseRisk = new HashMap<>();
            for (Object o : level.keySet()) {
                Integer risk_level = Integer.valueOf(o.toString());
                int count = Integer.parseInt(level.get(o).toString());
                if (Constant.HIGHT_LICENSE.equals(risk_level)) {
                    projectLicenseRisk.put(Constant.HIGHT_LICENSE, count);
                } else if (Constant.MID_LICENSE.equals(risk_level)) {
                    projectLicenseRisk.put(Constant.MID_LICENSE, count);
                } else if (Constant.LOW_LICENSE.equals(risk_level)) {
                    projectLicenseRisk.put(Constant.LOW_LICENSE, count);
                } else if (Constant.UNKNOWN_LICENSE.equals(risk_level)) {
                    projectLicenseRisk.put(Constant.UNKNOWN_LICENSE, count);
                }
            }

            //漏洞安全风险
            projectRes.put("vul_level", ImmutableMap.of(
                    VulLevelEnum.CRITICAL.getDescEn(), Optional.ofNullable(projectVul.get(Constant.SUPER_VUL)).orElse(0),
                    VulLevelEnum.HIGH.getDescEn(), Optional.ofNullable(projectVul.get(Constant.HIGH_VUL)).orElse(0),
                    VulLevelEnum.MID.getDescEn(), Optional.ofNullable(projectVul.get(Constant.MID_VUL)).orElse(0),
                    VulLevelEnum.LOW.getDescEn(), Optional.ofNullable(projectVul.get(Constant.LOW_VUL)).orElse(0),
                    VulLevelEnum.UNKNOWN.getDescEn(), Optional.ofNullable(projectVul.get(Constant.UNKNOWN_VUL)).orElse(0)
            ));
            //许可证风险等级
            projectRes.put("license_risk_level", ImmutableMap.of(
                    VulLevelEnum.HIGH.getDescEn(), Optional.ofNullable(projectLicenseRisk.get(Constant.HIGHT_LICENSE)).orElse(0),
                    VulLevelEnum.MID.getDescEn(), Optional.ofNullable(projectLicenseRisk.get(Constant.MID_LICENSE)).orElse(0),
                    VulLevelEnum.LOW.getDescEn(), Optional.ofNullable(projectLicenseRisk.get(Constant.LOW_LICENSE)).orElse(0),
                    VulLevelEnum.UNKNOWN.getDescEn(), Optional.ofNullable(projectLicenseRisk.get(Constant.UNKNOWN_LICENSE)).orElse(0)
            ));
        });
    }

    private Integer getEnterpriseId() {
        JSONObject userJson = ThreadLocalManager.getUserJson();
        Integer enterpriseId = ThreadLocalManager.getCurrentUserEnterpriseId(userJson);
        return enterpriseId;
    }


    public static String conLicense(String license) {
        List<String> licenses;
        String concluded = license;
        if ((license.contains("AND") && license.contains("OR")) || license.contains("WITH")) {
            return "NOASSERTION";
        }
        if (license.contains("AND") || license.contains("OR")) {
            String s = "AND";
            if (license.contains("OR")) {
                s = "OR";
            }
            license = license.replaceAll("[( , )]", "");
            licenses = Arrays.asList(license.split(s));

            if (licenses != null && licenses.size() > 0) {
                StringBuffer bf = new StringBuffer();
                bf.append("(");
                for (String l : licenses) {
//                String license = l.toLowerCase();
                    if ("Unknown".equals(l) || "Other".equals(l) || l.contains(" ")) {
                        continue;
                    }
                    String data = l;
                    if (!listedLicenseIds.contains(l) && l.length() > 11) {
                        data = l.substring(11, l.length());
                    }
                    bf.append(data + " " + s + " ");
                }
                bf.append(")");

                if (licenses.size() == 1) {
                    concluded = bf.toString().replaceAll("[( , )]", "").replace(s, "");
                } else {
                    concluded = bf.toString().replace(s + " )", ")");
                }
            }
        } else {
            if (!listedLicenseIds.contains(license) && license.length() > 11) {
                concluded = license.substring(11, license.length());
            }
        }


        return concluded.equals("") || concluded.equals(" ") ? "NONE" : concluded;
    }

    private List<String> licenseConvertList(String license) {
        List<String> list = new ArrayList<>();
        List<String> result = new ArrayList<>();
        if (license.contains("(") || license.contains(")")) {
            license = license.replaceAll("[( , )]", "");
            list = license.contains("AND") ? Arrays.asList(license.split("AND")) : license.contains("OR") ? Arrays.asList(license.split("OR")) : new ArrayList<>();
        } else {
            list.add(license);
        }

        for (String l : list) {
            if (!listedLicenseIds.contains(l) && l.length() > 11) {
                l = l.substring(11, l.length());
            }
            result.add(l);
        }

        return result;
    }

    private String spdxToJsonFile(SpdxToolsHelper.SerFileType fileType, String filePath, String toFilePath) throws Exception {
        if (SpdxToolsHelper.SerFileType.JSON.equals(fileType)) {
            return filePath;
        } else if (SpdxToolsHelper.SerFileType.TAG.equals(fileType) || SpdxToolsHelper.SerFileType.YAML.equals(fileType)) {
            SpdxConverter.convert(filePath, toFilePath, fileType, SpdxToolsHelper.SerFileType.JSON);
        } else if (SpdxToolsHelper.SerFileType.XML.equals(fileType)) {
            InputStreamReader is = new InputStreamReader(new FileInputStream(filePath), "utf-8");//获取xml文件，并且转为utf-8格式
            String xml = IOUtils.toString(is);
            cn.hutool.json.JSONObject jsonObject = JSONUtil.parseFromXml(xml);
            if (jsonObject == null) {
                throw new BusinessException("xml format json error!");
            }
            cn.hutool.json.JSONObject document = jsonObject.getJSONObject("Document");
            FileOutputStream fos = new FileOutputStream(toFilePath);
            OutputStreamWriter out = new OutputStreamWriter(fos);
            BufferedWriter bufferedWriter = new BufferedWriter(out);
            bufferedWriter.write(document.toString());
            bufferedWriter.close();
        }
        return toFilePath;
    }

    private static String getFormatCVSS(String cvss, int type) {//2-cvss2, 3-cvss3
        JSONObject jsonObject = new JSONObject();
        if (org.springframework.util.StringUtils.isEmpty(cvss)) {
            return JSONObject.toJSONString(jsonObject);
        }
        String[] split = cvss.split("/");
        for (String keyValue : split) {
            String[] split1 = keyValue.split(":");
            String key = String.valueOf(split1[0]);
            String value = String.valueOf(split1[1]);
            if ("AV".equals(key)) {
                jsonObject.put(key, formatCVSS_AV(value));
            } else if ("AC".equals(key)) {
                jsonObject.put(key, formatCVSS_AC(value));
            } else if ("Au".equals(key)) {
                jsonObject.put(key, formatCVSS_Au(value));
            } else if ("UI".equals(key)) {
                jsonObject.put(key, formatCVSS_UI(value));
            } else if ("S".equals(key)) {
                jsonObject.put(key, formatCVSS_S(value));
            } else if (type == 2 && ("C".equals(key) || "I".equals(key) || "A".equals(key))) {
                jsonObject.put(key, formatCVss2_ICA(value));
            } else if (type == 3 && ("C".equals(key) || "I".equals(key) || "A".equals(key) || "PR".equals(key))) {
                jsonObject.put(key, formatCVss3_ICA_PR(value));
            }
        }
        return JSONObject.toJSONString(jsonObject);
    }

    private static String formatCVSS_AV(String key) {
        if (org.springframework.util.StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NETWORK";
            case "A":
                return "ADJACENT_NETWORK";
            case "L":
                return "LOCAL";
            case "P":
                return "PHYSICAL";
        }
        return "";
    }

    private static String formatCVSS_AC(String key) {
        if (org.springframework.util.StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "L":
                return "LOW";
            case "M":
                return "MEDIUM";
            case "H":
                return "HIGH";
        }
        return "";
    }

    private static String formatCVSS_UI(String key) {
        if (org.springframework.util.StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "R":
                return "REQUIRED";
        }
        return "";
    }

    private static String formatCVSS_Au(String key) {
        if (org.springframework.util.StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "M":
                return "MULTIPLE";
            case "S":
                return "SINGLE";
        }
        return "";
    }

    private static String formatCVSS_S(String key) {
        if (org.springframework.util.StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "U":
                return "UNCHANGED";
            case "C":
                return "CHANGED";
        }
        return "";
    }

    private static String formatCVss2_ICA(String key) {
        if (StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "P":
                return "PARTIAL";
            case "C":
                return "COMPLETE";
        }
        return "";
    }

    private static String formatCVss3_ICA_PR(String key) {
        if (org.springframework.util.StringUtils.isEmpty(key)) {
            return "";
        }
        switch (key) {
            case "N":
                return "NONE";
            case "L":
                return "LOW";
            case "H":
                return "HIGH";
        }
        return "";
    }

}
